
#ifndef _TTG_EXTRAS_OPERATIONS_
#define _TTG_EXTRAS_OPERATIONS_

#include "Common/Math.h"
#include "Common/Errors.h"

namespace ttg_internal
{
	//Contains basic non-generic info about operation.
	class OperationInfo
	{
		public:
			//Defines type of returned value.
			enum OperationType
			{
				TTGFLOAT,			//float
				TTGVECTOR3,			//vec3f
				TTGMATRIX4X4,		//mat4x4f
				UNKNOWN				//wtf?
			};
			//Defines known operations.
			enum OperationName
			{
				UNARY_PLUS,			//+1
				UNARY_MINUS,		//-1
				ADDITION,			//1+1
				MULTIPLICATION,		//1*1
				SUBSTRACTION,		//1-1
				DIVISION			//1/1
			};
			//Returns type of output
			//E.g. output of 1.0f + 1.0f is FLOAT, vec3f(1.0f, 2.0f, 3.0f) * 1.0f is VECTOR3.
			virtual OperationType getType() = 0;
			//Creates and returns another instance of operation.
			//In case of error returns NULL.
			virtual OperationInfo *createInstance(OperationInfo *op1,
												  OperationInfo *op2,
												  OperationInfo *op3)
			{
				return NULL;
			}
			virtual ~OperationInfo()
					{ /*nothing*/ }
	};
}

namespace ttg
{
	namespace extras
	{
		typedef ttg_internal::OperationInfo OperationInfo;
		//Basic class for any operation.
		//Contains method calculate().
		template<class T>
		class Operation	:public ttg_internal::OperationInfo
		{
			public:
				//Calculates value of contained sub-value.
				virtual T calculate() = 0;
				//Returns true if operation is static (always returns the same value).
				virtual bool isStatic() = 0;
				//OperationInfo member.
				virtual OperationType getType()
				{
					return getTypeOf();
				}
				//Returns type of curent template specialization.
				static OperationType getTypeOf()
				{
					throw Error(Error::FATAL, "Operation", "getTypeOf",
						"Unknown type");
				}
		};

		template<>
		ttg_internal::OperationInfo::OperationType Operation<float>::getTypeOf()
		{
			return TTGFLOAT;
		}

		template<>
		ttg_internal::OperationInfo::OperationType Operation<math::vec3f>::getTypeOf()
		{
			return TTGVECTOR3;
		}

		template<>
		ttg_internal::OperationInfo::OperationType Operation<math::mat4x4f>::getTypeOf()
		{
			return TTGMATRIX4X4;
		}
	}
}

#endif
